#include <assert.h>
#include <ctype.h>
#include <locale.h>
#include <errno.h>
#include <float.h>
#include <limits.h>
#include <math.h>
#include <setjmp.h>
#include <signal.h>
#include <stdarg.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>


//*******   write   **********
void fputc_write_file(void)
{
    printf("***** fputc_write_file *****\n");
    FILE *fp = NULL;
    int ch;

    fp = fopen("./test.txt", "w+");
   for( ch = 33 ; ch <= 100; ch++ )
   {
    // ch -- 这是要被写入的字符。该字符以其对应的 int 值进行传递
      fputc(ch, fp);
   }
    fclose(fp);
}

int fputs_write_file(void)
{
    printf("***** fputs_write_file *****\n");
    int e = EXIT_SUCCESS;
    FILE *fp = NULL;
    // If the fopen() call fails for some reason, it returns a NULL value and sets the global errno variable value. 
    fp = fopen("./test.txt", "a+");
    /* Print error message and exit if fopen() failed */
    if (!fp)
    {
        perror("./test.txt");
        return EXIT_FAILURE;
    }

    /* Writes text to file. Unlike puts(), fputs() does not add a new-line.
     Similarly to
    fopen(), the fputs() function also sets the errno value if it fails, 
    though in this case the function returns EOF to indicate the fail (it otherwise returns a non-negative value).
     */
    if (fputs("\nThis is testing for fputs ...\n", fp) == EOF)
    {
        perror("./test.txt");
        e = EXIT_FAILURE;
    }

    // fputs("\nThis is testing for fputs ...\n", fp);
    // fclose(fp);
    /* Close file
    The fclose() function flushes any buffers, closes the file and frees the memory pointed to by FILE *. 
    The return value indicates completion just as fputs() does (though it returns '0' if successful), 
    again also setting the errno value in the case of a fail.
     */
    if (fclose(fp))
    {
        perror("./test.txt");
        return EXIT_FAILURE;
    }
    return e;
}

void fprintf_write_file(void)
{
    printf("***** fprintf_write_file *****\n");
    FILE *fp = NULL;
    fp = fopen("./test.txt", "a+");
    fprintf(fp, "This is testing for fprintf ...\n");
    fclose(fp);
}

//*******   read   **********

void fgetc_read_file(void)
{
    printf("***** fgetc_read_file *****\n");
    char c;
    FILE *fp = NULL;
    fp = fopen("./test.txt", "r");
    while(1)
    {   
        c = fgetc(fp);
        if ( feof(fp) )
        {
            break;
        }
        printf("%c", c);
    }
    fclose(fp);
}

int fgets_read_file(void)
{
    printf("***** fgets_read_file *****\n");
    #define MAX_LINE_LENGTH 255
    #define FILENAME "./test.txt"
    char line[MAX_LINE_LENGTH] = {0};
    unsigned int line_count = 0;

    FILE *fp = NULL;
    char buff[MAX_LINE_LENGTH];
    fp = fopen(FILENAME, "r");
    if (!fp)
    {
        perror(FILENAME);
        return EXIT_FAILURE;
    }
    /* Get each line until there are none left */
    while(fgets(line, MAX_LINE_LENGTH, fp))
    {
        /* Print each line */
        printf("line[%06d]: %s\n", ++line_count, line);

        /* Add a trailing newline to lines that don't already have one */
        if (line[strlen(line) - 1] != 'n' )
        {
            printf("\n");
        }
    }

    // fgets(buff, MAX_LINE_LENGTH, (FILE *)fp);
    // printf("%s", buff);
    /* Close file */
    if (fclose(fp))
    {
        perror(FILENAME);
        return EXIT_FAILURE;
    }
}

void fscanf_read_file(void)
{
    printf("***** fscanf_read_file *****\n");
    FILE *fp = NULL;
    char buff[255];
    fp = fopen("./test.txt", "r");
    fgets(buff, 255, (FILE *)fp);
    printf("%s", buff);
    fclose(fp);
}

void fgetc_fscanf_fgets(void)
{
    printf("***** fgetc_fscanf_fgets *****\n");
    FILE *fp = NULL;
    char buff[255];
    char c;

    fp = fopen("./test.txt", "r");

    c = fgetc(fp);
    printf("0 : %c\n", c);

    fscanf(fp, "%s", buff);
    printf("1: %s\n", buff );

    fgets(buff, 255, (FILE*)fp);
    printf("2: %s", buff );

    fgets(buff, 255, (FILE*)fp);
    printf("3: %s", buff );
    fclose(fp);
}


int getline_read_file(void)
{
    printf("***** getline_read_file *****\n");
    /* Open the file for reading */
    #define FILENAME "./test.txt"
    char *line_buf = NULL;
    size_t line_buf_size = 0;
    int line_count = 0;
    size_t line_size;
    size_t max;
    FILE *fp = fopen(FILENAME, "r");
    if (!fp)
    {
        fprintf(stderr, "Error opening file '%s' \n", FILENAME);
        return EXIT_FAILURE;
    }
    /* Get the first line of the file. */
    line_size = getline(&line_buf, &line_buf_size, fp);

    /* Loop through until we are done with the file. */
    // line_size is 4294967295 --> -1
    while ( line_size >= 0 && line_size < LONG_MAX)
    {
        /* Increment our line count */
        line_count++;

        /* Show the line details */
        printf("line[%06d]: chars=%06d, buf size=%06u, contents: %s\n", line_count, line_size,line_buf_size, line_buf);

        /* get the next line */
        line_size = getline(&line_buf, &line_buf_size, fp);
    }
    /* Free the allocated line buffer */
    free(line_buf);
    line_buf = NULL;

    /* Close the file now that we are done with it */
    fclose(fp);

    return EXIT_FAILURE;
}


void main(void)
{
    fputc_write_file();
    fputs_write_file();
    fprintf_write_file();

    fgetc_read_file();
    fgets_read_file();
    fscanf_read_file();

    fgetc_fscanf_fgets();
    getline_read_file();
    getline_read_file();
    system("pause");
}


/*
write:
    int fputc( int c, FILE *fp );
        把参数 c 的字符值写入到 fp 所指向的输出流中。如果写入成功，它会返回写入的字符，如果发生错误，则会返回 EOF
    int fputs( const char *s, FILE *fp );
         把以 null 结尾的字符串 s 写入到 fp 所指向的输出流中。如果写入成功，它会返回一个非负值，如果发生错误，则会返回 EOF。
    int fprintf(FILE *fp,const char *format, ...)
        把一个字符串写入到文件中
read:
    int fgetc( FILE * fp );
        从 fp 所指向的输入文件中读取一个字符。返回值是读取的字符，如果发生错误则返回 EOF
    char *fgets( char *buf, int n, FILE *fp );
        读取最后一个字符之前就遇到一个换行符 '\n' 或文件的末尾 EOF，则只会返回读取到的字符，包括换行符。
    int fscanf(FILE *fp, const char *format, ...)
        从文件中读取字符串，但是在遇到第一个空格和换行符时，它会停止读取。


二进制 I/O 函数
下面两个函数用于二进制输入和输出：

size_t fread(void *ptr, size_t size_of_elements, 
             size_t number_of_elements, FILE *a_file);
              
size_t fwrite(const void *ptr, size_t size_of_elements, 
             size_t number_of_elements, FILE *a_file);
*/